Skip to content

Redact environment variable values in vminitd debug logs - #813

Merged
crosbymichael merged 1 commit into
apple:mainfrom
vyncint:fix/redact-env-in-vminitd-logs
Jul 29, 2026
Merged

Redact environment variable values in vminitd debug logs#813
crosbymichael merged 1 commit into
apple:mainfrom
vyncint:fix/redact-env-in-vminitd-logs

Conversation

@vyncint

@vyncint vyncint commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Fixes #518.

What

vminitd logs the full OCI spec and exec process at debug level in ManagedContainer ("created bundle with spec …", "creating exec process with …"), which puts every NAME=value environment entry into the boot log. Environment variables routinely carry secrets, so container logs --boot web | grep PASSWORD reproduces the leak exactly as described in #518.

Rather than redacting at the call sites, this makes the redacted form the default rendering of the types that own an environment: Process and Hook conform to CustomStringConvertible with values masked and names kept. Spec and Hooks inherit it, because Swift's reflection-based description renders a nested value through that value's own description.

The effect is that any \(spec) or \(process) is safe without the author knowing this file exists, which is what stops a log line added later from reintroducing the leak. The two existing log sites are unchanged, so this no longer touches vminitd at all.

Two details worth calling out:

  • Codable is untouched. description governs text rendering only, so an encoded spec still carries the real values and nothing changes about what is written to disk or sent to the guest. The unredacted environment also remains available to callers through process.env.
  • description renders through a mirror rather than a hand-written field list. Process has 13 fields; listing them by hand would drop the rest from the log line and would rot as fields are added.

Verification

  • New SpecRedactionTests (9 tests) cover: a whole Spec interpolated into a log line never renders the values; String(describing:) and String(reflecting:) are redacted too; variable names survive; NAME-only inherit entries pass through; NAME= and values containing further = are masked whole; encoding round-trips with the real values; rendering does not mutate; and the other fields are still rendered.
  • Negative control: with the redaction disabled the suite fails with 13 issues, and the output shows the secret in the clear, reproducing [Bug]: vminitd logs can expose environment variable secrets #518.
  • Full ContainerizationOCITests passes, 58 tests in 9 suites.
  • swift format lint --strict --configuration .swift-format-nolint is clean, and swift format leaves both files unchanged.

Every line here is one I can explain and justify; the reasoning above is the complete rationale for each change.

@crosbymichael

Copy link
Copy Markdown
Contributor

Can you rebase on main to fix the SIGPIPE issue found in the tests?

@vyncint vyncint closed this Jul 27, 2026
@vyncint
vyncint force-pushed the fix/redact-env-in-vminitd-logs branch from cec005d to 50f7722 Compare July 27, 2026 21:20
@vyncint vyncint reopened this Jul 27, 2026
@vyncint

vyncint commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main (50f7722). The branch now includes #810, which added Tests/ContainerizationOSTests/IgnoreSIGPIPE.swift and the ignoreSIGPIPEForTests() calls in EpollTests, BidirectionalRelayTests and SocketTests — that is the SIGPIPE the Linux job was hitting. The old run died on closingWriteEndSignalsHangup() with exited with unexpected signal code 13, which lines up.

The rebase was content-free: git patch-id --stable is 6cf10e22 before and after, so the diff is byte-identical, still the same three files. Locally on the rebased tree, swift build --target ContainerizationOCI is clean and the four SpecRedactionTests pass.

Two things worth flagging, both my doing:

  • The force-push briefly left the branch level with main, so GitHub auto-closed the PR. I reopened it immediately and the head is now 5424632. Sorry for the timeline noise.
  • Because of that, the workflows are sitting at action_required and need an approval to run.

@vyncint

vyncint commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Hi @crosbymichael,

Following up on the rebase. Both workflows are still at action_required on
5424632 and have not run, so there is no CI result yet to confirm the SIGPIPE
fix.

That approval is the only thing blocking. No rush, just flagging it.

@vyncint
vyncint force-pushed the fix/redact-env-in-vminitd-logs branch from 5424632 to c339953 Compare July 29, 2026 08:13
@crosbymichael

Copy link
Copy Markdown
Contributor

@vyncint how do you think we can prevent future code from reintroducing this issue?

@vyncint

vyncint commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

@vyncint how do you think we can prevent future code from reintroducing this issue?

Hi @crosbymichael,

The current patch is opt-in, so a new log line would reintroduce the leak. I would
rather make the default safe and conform Process and Hook to CustomStringConvertible
with the redacted rendering, which covers interpolation anywhere since reflection
picks up nested descriptions. I checked on Swift 6.3 that Codable is unaffected, so
the encoded spec is unchanged and only rendered output differs. Happy to rework it
that way, with a test asserting a Spec carrying a secret never renders it.

@crosbymichael

Copy link
Copy Markdown
Contributor

@vyncint that sounds great. I think that is the correct move.

vminitd logs the OCI spec and the exec process at debug level, so every NAME=value environment entry ended up in the boot log (apple#518). Environment variables routinely carry secrets.

Conform Process and Hook to CustomStringConvertible with a rendering that masks environment values and keeps the names. Spec and Hooks inherit it, because reflection renders a nested value through its own description, so interpolating a spec is redacted whether or not the author knows to ask for it. The two existing log sites need no change.

Codable is untouched: an encoded spec still carries the real values, and process.env still returns them.
@vyncint
vyncint force-pushed the fix/redact-env-in-vminitd-logs branch from c339953 to 151dfc3 Compare July 29, 2026 15:43
@vyncint

vyncint commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Thanks. Pushed that version.

Process and Hook now conform to CustomStringConvertible with the redacted rendering, and Spec and Hooks inherit it since reflection renders a nested value through its own description. The two vminitd log lines are safe as they stand, so this no longer changes vminitd at all and the PR is down to the two new files.

Codable is untouched, so an encoded spec still carries the real values. Tests cover interpolation, String(describing:) and String(reflecting:), that variable names survive, and that encoding round-trips unchanged. With the redaction disabled they fail with the secret visible, reproducing #518. Full ContainerizationOCITests passes, 58 tests.

One gap worth naming: dump() and direct Mirror use bypass description, so those would still print the values. Nothing in the repo logs that way, but it is not airtight.

The workflows are still at action_required and have not run yet, so they need an approval when you have a moment.

@vyncint

vyncint commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

All checks are green on 151dfc3, including the Linux compile check and the signature verification.

@crosbymichael
crosbymichael merged commit ff44a5b into apple:main Jul 29, 2026
7 checks passed
@crosbymichael

Copy link
Copy Markdown
Contributor

Thanks for working through this with me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: vminitd logs can expose environment variable secrets

2 participants